import type {
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
  // AxiosError,
} from "axios";

import axios from "axios";
import { useLoadingStore, useAccessStore } from "@/store";
import { setHeaders } from "./auth";
import { preferences } from "@/config/preference";
import router from "@/router/index";

class ApiError extends Error {
  constructor(
    public readonly code: Exclude<number, 200>, // 业务错误码（排除200）
    public readonly success: false, // 固定为 false
    public readonly data: null, // 固定为 null
    public readonly msg: string // 错误信息
  ) {
    super(msg || `API Error (code: ${code})`);
    this.name = "ApiError"; // 方便调试时识别
  }
  static fromResponse(response: {
    code: number;
    success: boolean;
    data: any;
    msg: string;
  }): ApiError | never {
    // console.log("from: ", response);
    if (response.success) {
      throw new Error("Not an API error response!");
    }
    return new ApiError(response.code, false, null, response.msg);
  }
}

// console.log("-----: ", preferences.system.axiosBaseUrl);
const instance = axios.create({
  baseURL: preferences.system.axiosBaseUrl,
  timeout: 30000,
});

// 错误统一处理，目前分为两类错误1、后端返回的错误（后端有data返回, message消息提示）2、网络相关错误（AxiosError 一般后端没有data返回，notification通知）
// message（主动操作后的反馈提示） notification(页面角落，显示系统（全局）通知提醒)
async function requests<T>(config: AxiosRequestConfig): Promise<Requests.WrapperResult<T>> {
  const loadingStore = useLoadingStore();
  const accessStore = useAccessStore();
  const { extra: { loading = false, showError = true } = {} } = config;
  try {
    if (loading) {
      loadingStore.showLoading();
    }
    // await sleep(3000);
    const requestResult = await instance(config);
    console.log("", config.url, requestResult);
    return [null, requestResult.data.data as T];
  } catch (error: unknown) {
    // console.log("requests error: ", error);
    if (axios.isAxiosError(error)) {
      console.log("requests error axiosError: ", error);
      return [error, null];
    } else if (error instanceof ApiError) {
      if (401 === error.code) {
        router.push({ path: preferences.app.login });
        accessStore.accessToken && tipUtils.showError("登录已过期");
        accessStore.setAccessToken(null);
      } else {
        showError && tipUtils.showError(error.msg);
      }
      return [error, null];
    }
    return Promise.reject(error);
  } finally {
    if (loading) {
      loadingStore.hideLoading();
    }
  }
}

// 请求拦截器进入error情况：
// 1、拦截器内部抛出错误
// 2、前一个拦截器 reject 了 Promise
// 3、同步代码执行出错 （代码错误，例如代码未定义的变量访问方法或者属性）
// 4、请求配置无效（比如：config.url 为空）
instance.interceptors.request.use(
  (config: InternalAxiosRequestConfig): InternalAxiosRequestConfig => {
    // console.log("request-interceptors: ", config);
    const assignHeaders = setHeaders();
    Object.assign(config.headers, assignHeaders);
    return config;
  },
  (error: unknown) => {
    // console.log("request-interceptors error: ", error);
    if (axios.isAxiosError(error)) console.error("axios config error: %s", error);
    else if (error instanceof Error) console.error("code error: %s", error);
    else console.error("unknow error %s", error);
    return Promise.reject(error);
  }
);

// 响应拦截器进入error情况
// 1、AxiosError 请求失败（响应码不在axios有效响应码中（可以通过validateStatus自定义，默认是2xx））
// 2、Error 拦截器内部代码抛出错误
// 3、NetworkError（浏览器）网络断开、CORS 问题 (axios.isAxiosError(error) 判断结果也是true)
// 4、CanceledError（Axios 特有）	请求被取消
// 5、SyntaxError 响应数据解析失败（如 JSON 格式错误）
// 注：如果拦截器代码中又异步调用，则返回类型需要是Promise<T>
// 注：在响应拦截器onRejected函数中 return error(相当于恢复promise链) 外部会走then(), throw error、return Promise.reject(error) 会被catch
// 注：接口401的情况是 response.status == 200, 但是response.data {"code": 401,"success": false,"data": null,"msg": "请求未授权"}
instance.interceptors.response.use(
  (response: AxiosResponse): AxiosResponse | Promise<AxiosResponse> => {
    // console.log("response-interceptors: ", response);
    const {
      data: { code, success },
    } = response;
    if (code !== 200 || !success) {
      return Promise.reject(ApiError.fromResponse(response.data));
    }
    return response;
  },
  (error: unknown) => {
    if (axios.isAxiosError(error)) {
      console.error("isAxiosError: ", error);
      // 网络错误
      let { message, status, response } = error;
      if (message === "Network Error") message = "网络错误！";
      else if (message.includes("timeout")) message = "网络超时，请稍后重试！";
      else {
        // 服务器有响应，状态码非2xx，目前后端的返回的data.msg中会有原因
        // 404 No handler found for POST /blade-auth/captcha1
        // 405 Request method 'POST' not supported
        // console.error("request fail: ", error);
        // 后面补充
        switch (status) {
          case 403:
            message = "越权访问！";
            break;
          case 500:
            message = "服务器内部错误！";
            break;
          default:
            message = "未知错误！";
        }

        if (response?.data) return Promise.reject(ApiError.fromResponse(response.data));
      }
      // message = response?.data.msg ?? message;
    } else {
      console.error("内部错误！");
    }

    return Promise.reject(error);
  }
);
export default requests;
